package com.hmy.gateway.service;

import com.hmy.gateway.bo.request.ReqUserLogin;
import com.hmy.gateway.client.UaaClient;
import com.hmy.gateway.common.properties.UaaUrlProperties;
import com.hmy.gateway.constant.SecurityConstant;
import com.hmy.common.exception.ClientException;
import com.hmy.common.json.CcpJacksonkMapper;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.security.oauth2.OAuth2ClientProperties;
import org.springframework.http.*;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.common.util.OAuth2Utils;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;

import java.rmi.ServerException;
import java.util.HashMap;
import java.util.Map;

@Service
@Slf4j
public class OAuth2AuthenticationService {

    @Autowired
    private OAuth2ClientProperties oAuth2ClientProperties;

    @Autowired
    private UaaClient uaaClient;

    @Autowired
    @Qualifier("loadBalancedRestTemplate")
    private RestTemplate restTemplate;

    @Autowired
    private UaaUrlProperties uaaUrlProperties;

    private static final String TOKEN_INVALID = "Cannot convert access token to JSON";
    private static final String TOKEN_EXPIRED = "Token has expired";

    @SneakyThrows
    public OAuth2AccessToken authenticate(ReqUserLogin reqUserLogin) throws ServerException {
        try {
            String username = reqUserLogin.getUsername();
            String password = reqUserLogin.getPassword();
            Map<String, String> params = new HashMap<>();
            params.put(OAuth2Utils.CLIENT_ID, oAuth2ClientProperties.getClientId());
            params.put("client_secret", oAuth2ClientProperties.getClientSecret());
            params.put("username", username);
            params.put(SecurityConstant.PASSWORD, password);
            params.put(OAuth2Utils.GRANT_TYPE, SecurityConstant.PASSWORD);
            ResponseEntity<OAuth2AccessToken> oAuth2AccessTokenResponseEntity = uaaClient.postAccessToken(params);

            return oAuth2AccessTokenResponseEntity.getBody();
        } catch (HttpClientErrorException e) {
            // 自定义错误信息
            throw new ClientException(this.getErrorDescription(e.getStatusText()).toString());
        } catch (Exception e) {
            log.error(reqUserLogin.getUsername(),e);
            throw new ClientException("您的手机号/密码输入错误");

        }
    }

    public OAuth2AccessToken authenticate(String refreshTokenValue) {
        Map<String, String> params = new HashMap<>();
        params.put(OAuth2Utils.CLIENT_ID, oAuth2ClientProperties.getClientId());
        params.put("client_secret", oAuth2ClientProperties.getClientSecret());
        params.put(OAuth2Utils.GRANT_TYPE, OAuth2AccessToken.REFRESH_TOKEN);
        params.put(OAuth2AccessToken.REFRESH_TOKEN, refreshTokenValue);
        ResponseEntity<OAuth2AccessToken> oAuth2AccessTokenResponseEntity = uaaClient.postAccessToken(params);
        return oAuth2AccessTokenResponseEntity.getBody();
    }

    public Map<String, Object> checkToken(String token) throws ServerException, ClientException {
        try {
            log.info("token:{}", token);
            MultiValueMap<String, String> formParams = new LinkedMultiValueMap<>();
            formParams.set("token", token);
            ResponseEntity<Map> responseEntity = restTemplate.postForEntity(uaaUrlProperties.getCheckToken(), formParams, Map.class);
            return responseEntity.getBody();
        } catch (HttpClientErrorException ex) {
            boolean bad400 = ex.getStatusCode().equals(HttpStatus.BAD_REQUEST);
            Object errorDescription = getErrorDescription(ex.getResponseBodyAsString());
            if (bad400 && TOKEN_INVALID.equals(errorDescription)) {
                throw new ServerException("无效的token");
            } else if (bad400 && TOKEN_EXPIRED.equals(errorDescription)) {
                throw new ServerException("token已过期");
            }
            throw new ClientException("调用token校验异常");
        }


    }

    private Object getErrorDescription(String message) {
        Map map = null;
        try {
            map = CcpJacksonkMapper.convertStringToMap(message);
        } catch (com.hmy.common.exception.ServerException e) {

        }
        return String.valueOf(map.get("error_description"));
    }

}
